package com.quzitech.efest.view.chart;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.PathEffect;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.quzitech.efest.utils.Myutil;
import com.quzitech.efest.utils.xtimeUtil;

/**
 * Created by Dacer on 11/4/13. Edited by Lee youngchan 21/1/14 Edited by dector
 * 30-Jun-2014
 */
public class LineView extends View {
	private int mViewHeight;
	int mViewWidth;
	// drawBackground
	private boolean autoSetDataOfGird = true;
	private boolean autoSetGridWidth = true;
	private int dataOfAGird = 10;
	private int bottomTextHeight = 0;
	private ArrayList<String> bottomTextList = new ArrayList<String>();

	private ArrayList<ArrayList<Integer>> dataLists;
	private ArrayList<Integer> dataList;
	private ArrayList<Integer> xCoordinateList = new ArrayList<Integer>();
	private ArrayList<Integer> yCoordinateList = new ArrayList<Integer>();

	private ArrayList<ArrayList<Dot>> drawDotLists = new ArrayList<ArrayList<Dot>>();
	private ArrayList<Dot> drawDotList = new ArrayList<Dot>();

	private Paint bottomTextPaint = new Paint();
	private int bottomTextDescent;

	// circle dot
	Paint bigCirPaint;
	Paint smallCirPaint;

	Paint linePaint;
	// popup
	private Paint popupTextPaint = new Paint();
	private final int bottomTriangleHeight = 12;
	public boolean showPopup = true;

	private Dot pointToSelect;
	private Dot selectedDot;

	private int topLineLength = Myutil.dip2px(getContext(), 0);; // | | 鈫恡his
																	// -+-+-
	private int sideLineLength = Myutil.dip2px(getContext(), 45) / 3 * 2;// --+--+--+--+--+--+--
																			// 鈫憈his
	private int backgroundGridWidth = Myutil.dip2px(getContext(), 81);

	// Constants
	private final int popupTopPadding = Myutil.dip2px(getContext(), 2);
	private final int popupBottomMargin = 0;// Myutil.dip2px(getContext(), 1);
	private final int bottomTextTopMargin = 0;// Myutil.sp2px(getContext(),
												// 1);// 5
	Paint backgroundpaint;
	// herereererererer文字到边线的距离
	private final int bottomLineLength = Myutil.sp2px(getContext(), 20);

	private final int DOT_INNER_CIR_RADIUS = Myutil.dip2px(getContext(), 3);
	private final int DOT_OUTER_CIR_RADIUS = Myutil.dip2px(getContext(), 5);
	private final int MIN_TOP_LINE_LENGTH = Myutil.dip2px(getContext(), 12);
	private final int MIN_VERTICAL_GRID_NUM = 4;
	private final int MIN_HORIZONTAL_GRID_NUM = 4;
	private final int BACKGROUND_LINE_COLOR = Color.parseColor("#EEEEEE");
	private final int BOTTOM_TEXT_COLOR = Color.parseColor("#9B9A9B");

	public static final int SHOW_POPUPS_All = 1;
	public static final int SHOW_POPUPS_MAXMIN_ONLY = 2;
	public static final int SHOW_POPUPS_NONE = 3;

	private int showPopupType = SHOW_POPUPS_NONE;
	int verticalGridNum = 0;
	int verticalGridNumMin = 0;

	int MaxValue;
	int MinValue;
	String s;
	int[] intArray;
	int x;
	int y;
	float pmin;
	float pmax;
	Character ch;
	Rect r;
	int drawDotSize;
	double get;
	Rect popupTextRect;

	private List<Double> yList_want = new ArrayList<Double>();
	/**
	 * All the y should add this data
	 */
	private int Zero = 40;

	public void setShowPopup(int popupType) {
		this.showPopupType = popupType;
	}

	// 鞝愳劆響滌嫓
	private Boolean drawDotLine = false;
	// 霛检澑旎煬
	private String[] colorArray = { "#F29700", "#D52329", "#1abc9c" };
	// popup 背景 改后不需�?

	// onDraw optimisations
	private final Point tmpPoint = new Point();

	public void setDrawDotLine(Boolean drawDotLine) {
		this.drawDotLine = drawDotLine;
	}

	private Runnable animator = new Runnable() {
		@Override
		public void run() {
			boolean needNewFrame = false;
			for (ArrayList<Dot> data : drawDotLists) {
				for (Dot dot : data) {
					dot.update();
					if (!dot.isAtRest()) {
						needNewFrame = true;
					}
				}
			}
			if (needNewFrame) {
				postDelayed(this, 25);
			}
			invalidate();
		}
	};

	public LineView(Context context) {
		this(context, null);
	}

	public LineView(Context context, AttributeSet attrs) {
		super(context, attrs);
		popupTextPaint.setAntiAlias(true);
		popupTextPaint.setColor(Color.WHITE);
		popupTextPaint.setTextSize(Myutil.sp2px(getContext(), 13));
		popupTextPaint.setStrokeWidth(5);
		popupTextPaint.setTextAlign(Paint.Align.CENTER);

		bottomTextPaint.setAntiAlias(true);
		bottomTextPaint.setTextSize(Myutil.sp2px(getContext(), 14));
		bottomTextPaint.setTextAlign(Paint.Align.CENTER);
		bottomTextPaint.setStyle(Paint.Style.FILL);
		bottomTextPaint.setColor(BOTTOM_TEXT_COLOR);

		bigCirPaint = new Paint();
		bigCirPaint.setAntiAlias(true);
		bigCirPaint.setTextSize(Myutil.sp2px(getContext(), 14));
		bigCirPaint.setStrokeWidth(Myutil.dip2px(getContext(), 2.5f));
		// draw the outer while circle
		smallCirPaint = new Paint(bigCirPaint);
		smallCirPaint.setColor(Color.parseColor("#FFFFFF"));

		backgroundpaint = new Paint();
		backgroundpaint.setStyle(Paint.Style.STROKE);
		backgroundpaint.setStrokeWidth(Myutil.dip2px(getContext(), 1f));
		backgroundpaint.setColor(BACKGROUND_LINE_COLOR);
		PathEffect effects = new DashPathEffect(new float[] { 10, 5, 10, 5 }, 1);
		backgroundpaint.setPathEffect(effects);

		linePaint = new Paint();
		linePaint.setAntiAlias(true);

		popupTextRect = new Rect();
	}

	public void updateBottomTextList(int time) {
		for (int i = 0; i < 6; i++) {
			switch (i) {
			case 0:
				// this.bottomTextList.set(0, object);
				this.bottomTextList.set(0, "0");
				break;
			case 1:
				this.bottomTextList.set(1,
						xtimeUtil.time((int) ((double) time) * 1 / 5));
				// this.bottomTextList.set(1, "00:00");
				break;
			case 2:
				// this.bottomTextList.set(2, "00:00");
				this.bottomTextList.set(2,
						xtimeUtil.time((int) ((double) time) * 2 / 5));
				break;
			case 3:
				// this.bottomTextList.set(3, "00:00");
				this.bottomTextList.set(3,
						xtimeUtil.time((int) ((double) time) * 3 / 5));
				break;
			case 4:
				// this.bottomTextList.set(4, "00:00");
				this.bottomTextList.set(4,
						xtimeUtil.time((int) ((double) time) * 4 / 5));
				break;
			case 5:
				// this.bottomTextList.set(5, "00:00");
				this.bottomTextList.set(5, xtimeUtil.time(time));
				break;

			}
		}
		postInvalidate();
	}

	/**
	 * dataList will be reset when called is method.
	 * 
	 * @param bottomTextList
	 *            The String ArrayList in the bottom.
	 */
	public void updateYListWant(List<Double> ylist) {
		this.yList_want = ylist;
		postInvalidate();

	}

	public void setYListWant(List<Double> ylist) {
		this.yList_want = ylist;

	}

	public void setBottomTextList(ArrayList<String> bottomTextList) {
		this.dataList = null;
		this.bottomTextList = bottomTextList;

		Rect r = new Rect();
		int longestWidth = 0;
		String longestStr = "";
		bottomTextDescent = 0;
		for (String s : bottomTextList) {
			bottomTextPaint.getTextBounds(s, 0, s.length(), r);
			if (bottomTextHeight < r.height()) {
				bottomTextHeight = 0; // r.height();
			}
			if (autoSetGridWidth && (longestWidth < r.width())) {
				longestWidth = r.width() + Myutil.dip2px(getContext(), 6);

				longestStr = s;
			}
			if (bottomTextDescent < (Math.abs(r.bottom))) {
				bottomTextDescent = 0;// Math.abs(r.bottom);
			}
		}

		if (autoSetGridWidth) {
			if (backgroundGridWidth < longestWidth) {
				backgroundGridWidth = longestWidth
						+ (int) bottomTextPaint.measureText(longestStr, 0, 1);
			}
			if (sideLineLength < longestWidth / 2) {
				sideLineLength = longestWidth / 2;
			}
		}

	}

	/**
	 *
	 * @param dataLists
	 *            The Integer ArrayLists for showing, dataList.size() must <
	 *            bottomTextList.size()
	 */
	public void setDataList(ArrayList<ArrayList<Integer>> dataLists) {
		Log.v("vtlist", "i am in the postInvalidate");
		selectedDot = null;
		this.dataLists = dataLists;
		refreshXCoordinateList(getHorizontalGridNum());
		// for (ArrayList<Integer> list : dataLists) {
		// if (list.size() > bottomTextList.size()) {
		// throw new RuntimeException("dacer.LineView error:"
		// + " dataList.size() > bottomTextList.size() !!!");
		// }
		// }
		int biggestData = 0;
		for (ArrayList<Integer> list : dataLists) {
			if (autoSetDataOfGird) {
				for (Integer i : list) {
					if (biggestData < i) {
						biggestData = i;
					}
				}
			}
			dataOfAGird = 1;
			while (biggestData / 10 > dataOfAGird) {
				dataOfAGird *= 10;
			}
		}

		refreshAfterDataChanged();
		showPopup = true;
		setMinimumWidth(0); // It can help the LineView reset the Width,
							// I don't know the better way..
		postInvalidate();
	}

	private void refreshAfterDataChanged() {
		verticalGridNum = getVerticalGridlNum();
		refreshTopLineLength(verticalGridNum);
		refreshYCoordinateList(verticalGridNum);
		refreshDrawDotList(verticalGridNum);
	}

	private int getVerticalGridlNum() {
		verticalGridNum = MIN_VERTICAL_GRID_NUM;
		verticalGridNumMin = 10000;
		if (dataLists != null && !dataLists.isEmpty()) {
			for (ArrayList<Integer> list : dataLists) {
				for (Integer integer : list) {
					if (verticalGridNum < (integer + 1)) {

						verticalGridNum = intUp(integer);

					}
					if (verticalGridNumMin > (integer)) {
						verticalGridNumMin = intDown(integer);
					}
				}
			}
		}
		return verticalGridNum;
	}

	private int intDown(int intStr) {
		s = String.valueOf(intStr);
		intArray = new int[s.length()];
		for (int i = 0; i < s.length(); i++) {
			ch = s.charAt(i);
			intArray[i] = Integer.parseInt(ch.toString());
		}
		if (s.length() <= 2) {
			// d = (intArray[0] + 1) * (Math.pow(10, s.length() - 1));
			return 0;
		} else if (s.length() == 3) {
			if ((intArray[0] > 1)) {
				return (int) ((intArray[0] - 1) * (Math.pow(10, s.length() - 1)));
			} else {
				return 100;
			}

		} else {
			return (int) ((intArray[0]) * (Math.pow(10, s.length() - 1)) + (intArray[1] - 1)
					* (Math.pow(10, s.length() - 2)));

		}

	}

	private int intUp(int intStr) {
		s = String.valueOf(intStr);
		intArray = new int[s.length()];
		for (int i = 0; i < s.length(); i++) {
			ch = s.charAt(i);
			intArray[i] = Integer.parseInt(ch.toString());
		}

		if (s.length() <= 3) {
			return (int) ((intArray[0] + 2) * (Math.pow(10, s.length() - 1)));
		} else {
			return (int) ((intArray[0]) * (Math.pow(10, s.length() - 1)) + (intArray[1] + 2)
					* (Math.pow(10, s.length() - 2)));

		}

	}

	//
	private int getHorizontalGridNum() {
		int horizontalGridNum = bottomTextList.size() - 1;
		if (horizontalGridNum < MIN_HORIZONTAL_GRID_NUM) {
			horizontalGridNum = MIN_HORIZONTAL_GRID_NUM;
		}
		return horizontalGridNum;
	}

	private void refreshXCoordinateList(int horizontalGridNum) {
		xCoordinateList.clear();
		for (int i = 0; i < dataLists.get(1).size(); i++) {
			xCoordinateList.add(dataLists.get(1).get(i));
		}

	}

	private void refreshYCoordinateList(int verticalGridNum) {
		yCoordinateList.clear();
		for (int i = 0; i < (verticalGridNum + 1); i++) {
			yCoordinateList.add(((mViewHeight) * i / (verticalGridNum)));
		}
	}

	private void refreshDrawDotList(int verticalGridNum) {

		int height = topLineLength
				+ (mViewHeight - topLineLength - bottomTextHeight
						- bottomTextTopMargin - bottomLineLength - bottomTextDescent);
		if (dataLists != null && !dataLists.isEmpty()
				&& !dataLists.get(dataLists.size() - 1).isEmpty()) {
			if (drawDotLists.size() == 0) {
				for (int k = 0; k < 1; k++) {
					drawDotLists.add(new ArrayList<LineView.Dot>());
				}
			}
			// 实际值x范围 (float) 1.5*sideLineLength-------(mViewWidth -
			// sideLineLength) ( mwidth-2.5sideLineLength)/总分钟*x分钟数+ (float) 1.5
			// * sideLineLength 总分钟和分钟数计算方法为减去最前面分钟数
			// 实际值y范围 Zero-------i y的计算 (i-zero)/1.5*（y-3.0）+zero
			// (总高度)/份数1.5v
			for (int k = 0; k < 1; k++) {
				drawDotSize = drawDotLists.get(k).isEmpty() ? 0 : drawDotLists
						.get(k).size();

				for (int i = 0; i < dataLists.get(k).size(); i++) {
					x = (int) ((mViewWidth - 2.5 * sideLineLength) / 1000
							* xCoordinateList.get(i) + (float) 1.5
							* sideLineLength);
					get = (double) (dataLists.get(k).get(i)) / 100;

					y = (int) ((((double) height - Zero) / (yList_want.get(3) - yList_want
							.get(0)))
							* ((yList_want.get(3) - yList_want.get(0)) - (get - yList_want
									.get(0))) + Zero);
					// y = (int) ((height - Zero) / 1.3 * (1.3 - (get - 3.0)) +
					// Zero);
					// Log.v("test",
					// y
					// +
					// "-------------------------------------------------------------");
					if (i > drawDotSize - 1) {
						// 霃勴姼毽姢韸鸽�? 於旉皜頃滊嫟.
						drawDotLists.get(k)
								.add(new Dot(x, 0, x, y, dataLists.get(k)
										.get(i), k));
					} else {
						// 霃勴姼毽姢韸胳�? 韮�瓴熿�? 靹れ爼頃滊嫟.
						drawDotLists.get(k).set(
								i,
								drawDotLists
										.get(k)
										.get(i)
										.setTargetData(x, y,
												dataLists.get(k).get(i), k));
					}
				}

				int temp = drawDotLists.get(k).size() - dataLists.get(k).size();
				for (int i = 0; i < temp; i++) {
					drawDotLists.get(k).remove(drawDotLists.get(k).size() - 1);
				}
			}
		}
		removeCallbacks(animator);
		post(animator);
	}

	private void refreshTopLineLength(int verticalGridNum) {
		// For prevent popup can't be completely showed when
		// backgroundGridHeight is too small.
		// But this code not so good.
		if ((mViewHeight - topLineLength - bottomTextHeight - bottomTextTopMargin)
				/ (verticalGridNum + 2) < getPopupHeight()) {
			topLineLength = getPopupHeight() + DOT_OUTER_CIR_RADIUS
					+ DOT_INNER_CIR_RADIUS + 2;
		} else {
			topLineLength = MIN_TOP_LINE_LENGTH;
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// drawBackgroundLines(canvas);
		drawBackgroundLines(canvas);
		drawLines(canvas);
		// drawDots(canvas);

		// for (int k = 0; k < drawDotLists.size(); k++) {
		// MaxValue = Collections.max(dataLists.get(k));
		// MinValue = Collections.min(dataLists.get(k));
		// for (Dot d : drawDotLists.get(k)) {
		// drawPopup(canvas, String.valueOf(d.data),
		// d.setupPoint(tmpPoint));
		//
		// }
		// }

	}

	/**
	 *
	 * @param canvas
	 *            The canvas you need to draw on.
	 * @param point
	 *            The Point consists of the x y coordinates from left bottom to
	 *            right top. Like is
	 * 
	 * @param PopupColor
	 *            the int popupcolor is never user in this file that was edited
	 *            for wssa
	 * 
	 * 
	 * 
	 */
	private void drawPopup(Canvas canvas, String num, Point point) {
		boolean singularNum = (num.length() == 1);
		int sidePadding = Myutil.dip2px(getContext(), singularNum ? 8 : 5);
		x = point.x;
		y = point.y - Myutil.dip2px(getContext(), 6);

		popupTextPaint.getTextBounds(num, 0, num.length(), popupTextRect);

		canvas.drawText(num, x, y - bottomTriangleHeight - popupBottomMargin,
				popupTextPaint);
	}

	private int getPopupHeight() {
		Rect popupTextRect = new Rect();
		popupTextPaint.getTextBounds("9", 0, 1, popupTextRect);
		r = new Rect(-popupTextRect.width() / 2, -popupTextRect.height()
				- bottomTriangleHeight - popupTopPadding * 2
				- popupBottomMargin, +popupTextRect.width() / 2,
				+popupTopPadding - popupBottomMargin);
		return r.height();
	}

	// 霃勴姼攴鸽Μ旮�?
	private void drawDots(Canvas canvas) {

		if (drawDotLists != null && !drawDotLists.isEmpty()) {
			for (int k = 0; k < drawDotLists.size(); k++) {
				bigCirPaint.setColor(Color.parseColor(colorArray[k % 3]));
				for (Dot dot : drawDotLists.get(k)) {

					canvas.drawCircle(dot.x, dot.y, DOT_OUTER_CIR_RADIUS,
							bigCirPaint);
					// Log.v("testwhickline", dot.linenumber + "");

				}
			}
		}
	}

	// 靹犼犯毽赴
	private void drawLines(Canvas canvas) {

		linePaint.setStrokeWidth(Myutil.dip2px(getContext(), 2));
		for (int k = 0; k < drawDotLists.size(); k++) {
			linePaint.setColor(Color.parseColor(colorArray[k % 3]));

			for (int i = 0; i < drawDotLists.get(k).size() - 1; i++) {
				canvas.drawLine(drawDotLists.get(k).get(i).x,
						drawDotLists.get(k).get(i).y,
						drawDotLists.get(k).get(i + 1).x, drawDotLists.get(k)
								.get(i + 1).y, linePaint);
			}
		}
	}

	private void drawYText(Canvas canvas, int i) {

		// 画Y坐标
		canvas.drawText(yList_want.get(0) + "", (float) 0.75 * sideLineLength,
				i, bottomTextPaint);
		canvas.drawText(yList_want.get(3) + "", (float) 0.75 * sideLineLength,
				Zero, bottomTextPaint);
		canvas.drawText(yList_want.get(2) + "", (float) 0.75 * sideLineLength,
				(float) ((i - Zero) * (double) 1 / 3 + Zero), bottomTextPaint);
		canvas.drawText(yList_want.get(1) + "", (float) 0.75 * sideLineLength,
				(float) ((i - Zero) * (double) 2 / 3 + Zero), bottomTextPaint);
	}

	private void drawBottomText(Canvas canvas) {

		if (bottomTextList != null && bottomTextList.size() != 0) {

			canvas.drawText(bottomTextList.get(0),
					(float) 1.5 * sideLineLength, mViewHeight
							- bottomTextDescent, bottomTextPaint);

			canvas.drawText(bottomTextList.get(1), (float) 1.5 * sideLineLength
					+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 1
					/ 5, mViewHeight - bottomTextDescent, bottomTextPaint);
			canvas.drawText(bottomTextList.get(2), (float) 1.5 * sideLineLength
					+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 2
					/ 5, mViewHeight - bottomTextDescent, bottomTextPaint);
			canvas.drawText(bottomTextList.get(3), (float) 1.5 * sideLineLength
					+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 3
					/ 5, mViewHeight - bottomTextDescent, bottomTextPaint);
			canvas.drawText(bottomTextList.get(4), (float) 1.5 * sideLineLength
					+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 4
					/ 5, mViewHeight - bottomTextDescent, bottomTextPaint);

			canvas.drawText(bottomTextList.get(5),
					(mViewWidth - sideLineLength), mViewHeight
							- bottomTextDescent, bottomTextPaint);

			// 实际值x范围 (float) 1.5*sideLineLength-------(mViewWidth -
			// sideLineLength) ( mwidth-2.5sideLineLength)/总分钟*x分钟数+ (float) 1.5
			// * sideLineLength 总分钟和分钟数计算方法为减去最前面分钟数
			// 实际值y范围 Zero-------i y的计算 (i-zero)/1.5*（y-3.0）+zero
			// (总高度)/份数1.5v
		}
	}

	private void drawBackgroundLines(Canvas canvas) {
		int i = topLineLength
				+ (mViewHeight - topLineLength - bottomTextHeight
						- bottomTextTopMargin - bottomLineLength - bottomTextDescent);
		// draw bottom text
		// add another 60 , the x also add
		drawBottomText(canvas);
		// if (bottomTextList != null && bottomTextList.size() != 0) {
		//
		// canvas.drawText(bottomTextList.get(0),
		// (float) 1.5 * sideLineLength, mViewHeight
		// - bottomTextDescent, bottomTextPaint);
		//
		// canvas.drawText(bottomTextList.get(1), (float) 1.5 * sideLineLength
		// + (mViewWidth - (float) 2.5 * sideLineLength) * (float) 1
		// / 5, mViewHeight - bottomTextDescent, bottomTextPaint);
		// canvas.drawText(bottomTextList.get(2), (float) 1.5 * sideLineLength
		// + (mViewWidth - (float) 2.5 * sideLineLength) * (float) 2
		// / 5, mViewHeight - bottomTextDescent, bottomTextPaint);
		// canvas.drawText(bottomTextList.get(3), (float) 1.5 * sideLineLength
		// + (mViewWidth - (float) 2.5 * sideLineLength) * (float) 3
		// / 5, mViewHeight - bottomTextDescent, bottomTextPaint);
		// canvas.drawText(bottomTextList.get(4), (float) 1.5 * sideLineLength
		// + (mViewWidth - (float) 2.5 * sideLineLength) * (float) 4
		// / 5, mViewHeight - bottomTextDescent, bottomTextPaint);
		//
		// canvas.drawText(bottomTextList.get(5),
		// (mViewWidth - sideLineLength), mViewHeight
		// - bottomTextDescent, bottomTextPaint);
		//
		// // 实际值x范围 (float) 1.5*sideLineLength-------(mViewWidth -
		// // sideLineLength) ( mwidth-2.5sideLineLength)/总分钟*x分钟数+ (float) 1.5
		// // * sideLineLength 总分钟和分钟数计算方法为减去最前面分钟数
		// // 实际值y范围 Zero-------i y的计算 (i-zero)/1.5*（y-3.0）+zero
		// // (总高度)/份数1.5v
		// }
		drawYText(canvas, i);
		// 画竖线
		canvas.drawLine((float) 1.5 * sideLineLength
				+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 1 / 5,
				Zero, (float) 1.5 * sideLineLength
						+ (mViewWidth - (float) 2.5 * sideLineLength)
						* (float) 1 / 5, i, bottomTextPaint);
		canvas.drawLine((float) 1.5 * sideLineLength
				+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 2 / 5,
				Zero, (float) 1.5 * sideLineLength
						+ (mViewWidth - (float) 2.5 * sideLineLength)
						* (float) 2 / 5, i, bottomTextPaint);
		canvas.drawLine((float) 1.5 * sideLineLength
				+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 3 / 5,
				Zero, (float) 1.5 * sideLineLength
						+ (mViewWidth - (float) 2.5 * sideLineLength)
						* (float) 3 / 5, i, bottomTextPaint);
		canvas.drawLine((float) 1.5 * sideLineLength
				+ (mViewWidth - (float) 2.5 * sideLineLength) * (float) 4 / 5,
				Zero, (float) 1.5 * sideLineLength
						+ (mViewWidth - (float) 2.5 * sideLineLength)
						* (float) 4 / 5, i, bottomTextPaint);

		// �?上面
		canvas.drawLine((float) 1.5 * sideLineLength + 0, Zero, mViewWidth
				- (float) 1 * sideLineLength, Zero, bottomTextPaint);

		// �?底下
		canvas.drawLine((float) 1.5 * sideLineLength + 0, i, mViewWidth
				- (float) 1 * sideLineLength, i, bottomTextPaint);

		canvas.drawLine((float) 1.5 * sideLineLength + 0f, (float) ((i - Zero)
				* (double) 1 / 3 + Zero), mViewWidth - (float) 1
				* sideLineLength, (float) ((i - Zero) * (double) 1 / 3 + Zero),
				bottomTextPaint);
		canvas.drawLine((float) 1.5 * sideLineLength + 0f, (float) ((i - Zero)
				* (double) 2 / 3 + Zero), mViewWidth - (float) 1
				* sideLineLength, (float) ((i - Zero) * (double) 2 / 3 + Zero),
				bottomTextPaint);

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		mViewWidth = measureWidth(widthMeasureSpec);
		mViewHeight = measureHeight(heightMeasureSpec) - 10;

		// mViewHeight = MeasureSpec.getSize(measureSpec);
		refreshAfterDataChanged();
		setMeasuredDimension(mViewWidth, mViewHeight);
	}

	private int measureWidth(int measureSpec) {
		int horizontalGridNum = getHorizontalGridNum();
		int preferred = backgroundGridWidth * horizontalGridNum
				+ sideLineLength * 2;
		return getMeasurement(measureSpec, preferred);
	}

	private int measureHeight(int measureSpec) {
		int preferred = 0;
		return getMeasurement(measureSpec, preferred);
	}

	private int getMeasurement(int measureSpec, int preferred) {
		int specSize = MeasureSpec.getSize(measureSpec);
		int measurement;
		switch (MeasureSpec.getMode(measureSpec)) {
		case MeasureSpec.EXACTLY:
			measurement = specSize;
			break;
		case MeasureSpec.AT_MOST:
			measurement = Math.min(preferred, specSize);
			break;
		default:
			measurement = preferred;
			break;
		}
		return measurement;
	}

	private Dot findPointAt(int x, int y) {
		if (drawDotLists.isEmpty()) {
			return null;
		}

		final int width = backgroundGridWidth / 2;
		final Region r = new Region();

		for (ArrayList<Dot> data : drawDotLists) {
			for (Dot dot : data) {
				final int pointX = dot.x;
				final int pointY = dot.y;

				r.set(pointX - width, pointY - width, pointX + width, pointY
						+ width);
				if (r.contains(x, y)) {
					return dot;
				}
			}
		}

		return null;
	}

	class Dot {
		int x;
		int y;
		int data;
		int targetX;
		int targetY;
		int linenumber;
		int velocity = Myutil.dip2px(getContext(), 18);

		Dot(int x, int y, int targetX, int targetY, Integer data, int linenumber) {
			this.x = x;
			this.y = y;
			this.linenumber = linenumber;
			setTargetData(targetX, targetY, data, linenumber);
		}

		Point setupPoint(Point point) {
			point.set(x, y);
			return point;
		}

		Dot setTargetData(int targetX, int targetY, Integer data, int linenumber) {
			this.targetX = targetX;
			this.targetY = targetY;
			this.data = data;
			this.linenumber = linenumber;
			return this;
		}

		boolean isAtRest() {
			return (x == targetX) && (y == targetY);
		}

		void update() {
			x = updateSelf(x, targetX, velocity);
			y = updateSelf(y, targetY, velocity);
		}

		private int updateSelf(int origin, int target, int velocity) {
			if (origin < target) {
				origin += velocity;
			} else if (origin > target) {
				origin -= velocity;
			}
			if (Math.abs(target - origin) < velocity) {
				origin = target;
			}
			return origin;
		}
	}
}
